package org.jackysoft.interceptor;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jackysoft.entity.User;
import org.jackysoft.entity.nosql.OperationLog;
import org.jackysoft.util.OperationType;
import org.jackysoft.util.SpringSecurityUtils;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class AbstractInterceptor implements Interceptor {

	/**
	 * 
	 */
	private static final long serialVersionUID = -8509988306862120381L;

	protected final static String ACTION_GET_SERVICE = "getService";
	protected final static String ACTION_GET_BEAN = "getBean";
	protected final static String ACTION_GET_BEANS = "getBeans";
	protected final static String ACTION_SET_BEAN = "setBean";
	protected final static String ACTION_SET_BEANS = "setBeans";
	protected final static String SERVICE_INSERT_BEAN_ = "create";
	protected final static String SERVICE_REMOVE_BEAN_ = "remove";
	protected final static String SERVICE_UPDATE_BEAN_ = "update";
	protected final static String SERVICE_GET_BEAN_ = "get";
	protected final static String SERVICE_GETS_BEAN_ = "gets";
	protected final static Log logger = LogFactory.getLog(AbstractInterceptor.class);
	protected final static String VALIDATED = "validated";
	protected Object service;
	protected Object bean;
	protected Object beans;
	protected Class  beanType;

	private static Validator validator;

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

	@Override
	public void init() {

	}

	static {
		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
		validator = factory.getValidator();
	}

	@Override
	public String intercept(ActionInvocation ai) throws Exception {
		Object action = ai.getAction();
		bean     =  parseBean(action, "bean");	
		beans    =  parseBean(action, "beans");
		service  =  parseBean(action, "service");
		beanType =  (Class) parseBean(action, "type");
		if(beanType==null)
			beanType = (Class) parseBean(service,"type");
		if(beanType==null)
			logger.warn("found neither Service nor Action instance has validate type property, some operation need this ,please get it ");
		forLogged(action);
		try {
			Boolean validating = (Boolean) PropertyUtils.getProperty(action,
					"validating");
			if (validating) {
				ValidateResult vrst = validate(bean);
				if(!vrst.passed){
					PropertyUtils.setProperty(action, "jsonContent", vrst.result);
					return VALIDATED;
				}
			}			
		} catch (NoSuchMethodException e) {
			logger.warn(e.toString());
			//throw e;
		}

		
		return null;
	}

	protected Object parseBean(Object target, String beanNames)
			throws NoSuchMethodException {
		Object bean = null;

		try {
			bean = PropertyUtils.getProperty(target, beanNames);

		} catch (NoSuchMethodException e) {
			logger.error(e);
			// throw e;
		} catch (IllegalAccessException e) {
			logger.error(e);
		} catch (InvocationTargetException e) {
			logger.error(e);
		}

		return bean;
	}
	
	protected void setProperty(Object target, String name,Object value)
			throws NoSuchMethodException {
		
		
		try {
			
			PropertyUtils.setProperty(target, name, value);
			
		} catch (NoSuchMethodException e) {
			logger.error(e);
			// throw e;
		} catch (IllegalAccessException e) {
			logger.error(e);
		} catch (InvocationTargetException e) {
			logger.error(e);
		}		
		
	}

	protected ValidateResult validate(Object object) {
		Set<ConstraintViolation<Object>> conts = validator.validate(object);
		String vs = "";
		ValidateResult vr = new ValidateResult();
		for (ConstraintViolation<Object> cs : conts) {
			vs += "<li>" + cs.getMessage() + "</li>";
		}
		vr.passed = conts.isEmpty();
		vr.result = vs;
		return vr;

	}
	protected void forLogged(Object action) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException{
		 
		boolean loged = action.getClass().isAnnotationPresent(org.jackysoft.annotations.Logger.class);
			if(loged){
				User user = SpringSecurityUtils.getCurrentUser();
				org.jackysoft.annotations.Logger loginfo = action.getClass().getAnnotation(org.jackysoft.annotations.Logger.class);
			    String objectName = loginfo.label();
			    Class cls = getClass();
			    String opr= operationName(cls);
			    OperationLog oprlog = new OperationLog();
			    oprlog.setCreateDate(new Date());
			    oprlog.setName(opr);
			    OperationType logType = loginfo.logType();
			    oprlog.setOprType(logType);
			    oprlog.setDetails("用户 "+user.getLocalName()+"  ["+user.getUsername()+"] "+opr + objectName+" 详细:"+bean);
			    Method logMethod = action.getClass().getMethod("logAction",OperationLog.class);
			    logMethod.invoke(action, oprlog);
			}
	}
	
	String operationName(Class cls){
		
		if(cls.isAssignableFrom(GetInterceptor.class)){
			return " 查看 ";
		}
		
		if(cls.isAssignableFrom(CreateInterceptor.class)){
			return " 创建 ";
		}
		
		if(cls.isAssignableFrom(UpdateInterceptor.class)){
			return " 修改 ";
		}
		
		if(cls.isAssignableFrom(RemoveInterceptor.class)){
			return " 删除 ";
		}
		
		return " 未知 ";
	}
}

class ValidateResult {
	/**true 则通过验证 via false*/
	public boolean passed;
	
	/**结果字符串*/
	public String result;
}
